import { ref, watch, computed } from 'vue'
import * as THREE from 'three'
import _ from 'lodash'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'
import { MeshLine, MeshLineMaterial } from 'three.meshline'
import * as ThreeMath from 'three-math'
import { DeclareLine, GroupType, State } from './type'
import { scene, camera } from './index'
import { markingPos, dotListPos, provinceList, getDotListPos } from './config'

// 添加或者获取地图上展示
const FLYINGLINEGROUP = 'flyingLineGroup'
const EARTHLABEGROUP = 'earthLableGroup'
const DOTGROUP = 'dotGroup'
const PROVINCELABELGROUP = 'provinceLabelGroup'

// 地图的大小
const earthBallSize = 1.028

// 各种状态
const state: State = {
  opacity: 0,
  modalLeft: 0,
  modalTap: 0,
  eventType: 1,
  provinceName: '',
  provinceValue: 0,
  cameraPos: null
}

// 经纬度转换函数
const getPosition = (longitude: any, latitude: any, radius: any) => {
  const lg = ThreeMath.Math.degToRad(longitude)
  const lt = ThreeMath.Math.degToRad(latitude)
  const temp = radius * Math.cos(lt)
  const x = temp * Math.sin(lg)
  const y = radius * Math.sin(lt)
  const z = temp * Math.cos(lg)
  return { x, y, z }
}

// 计算球体上两个点的中点
const getVCenter = (v1: any, v2: any) => {
  const v = v1.add(v2)
  return v.divideScalar(2)
}

// 计算球体两点向量固定长度的点
const getLenVcetor = function (v1: any, v2: any, len: any) {
  const v1v2Len = v1.distanceTo(v2)
  return v1.lerp(v2, len / v1v2Len)
}

// 添加轨迹函数
const createLine = (
  v0: any,
  v3: any,
  dashArray: any,
  lineWidth: any,
  color: any
): DeclareLine => {
  const angle = (v0.angleTo(v3) * 180) / Math.PI
  const aLen = angle * 0.013 * (1 - angle / (Math.PI * 90))
  const hLen = angle * angle * 1.23 * (1 - angle / (Math.PI * 90))
  // 创建一个三维向量对象表示线段中点
  const p0 = new THREE.Vector3(0, 0, 0)
  // 法线向量 射线Ray
  const rayLine = new THREE.Ray(p0, getVCenter(v0.clone(), v3.clone()))
  // 顶点坐标 new THREE.Ray().at(t: '射线方向到起点长度为t点', target: '')
  const target = new THREE.Vector3(0, 0, 0)
  const vtop = rayLine.at(hLen / rayLine.at(1, target).distanceTo(p0), target)
  // 控制点坐标
  const v1 = getLenVcetor(v0.clone(), vtop, aLen)
  const v2 = getLenVcetor(v3.clone(), vtop, aLen)
  // 绘制贝塞尔曲线 三维三次贝塞尔曲线（CubicBezierCurve3  // v0 – 起点  // v1 – 第一个控制点  // v2 – 第二个控制点  // v3 – 终点
  const curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3)
  const points = curve.getPoints(100)
  const geometry = new THREE.BufferGeometry().setFromPoints(points)
  const line = new MeshLine()
  line.setGeometry(geometry)
  const material = new MeshLineMaterial({
    color: color || '#00FFFF',
    lineWidth: lineWidth || 0.003,
    transparent: true,
    opacity: 1,
    dashArray: dashArray || 0
  })

  return {
    curve: curve,
    lineMesh: new THREE.Mesh(line.geometry, material)
  }
}

// 生成线条
const getFlyingLines = (
  data: any,
  earthBallSize: number,
  visible = true,
  groupName: string
) => {
  const rootPosition = getPosition(
    data[0].pos[0] - 90,
    data[0].pos[1],
    earthBallSize
  )
  const { x, y, z } = rootPosition
  const rootPos = new THREE.Vector3(x, y, z)
  const groupLines = new THREE.Group()
  const loop = function (items: any, parentPos: any) {
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      const position = getPosition(
        item.pos[0] - 90,
        item.pos[1],
        earthBallSize
      )
      const ballPos = new THREE.Vector3(position.x, position.y, position.z)

      let line: null | DeclareLine = null
      switch (item.level) {
        case 1:
          line = createLine(parentPos, ballPos, 0, 0.003, '#00FFFF')
          break
        case 2:
          line = createLine(parentPos, ballPos, 0.1, 0.002, '#00FFFF')
          break
        default:
          line = createLine(parentPos, ballPos, 0, 0.003, '#00FFFF')
          break
      }

      if (line) {
        line.lineMesh.visible = visible
        groupLines.add(line.lineMesh)
      }

      if (item.children && item.children.length > 0) {
        loop(item.children, ballPos)
      }
    }
  }
  loop(data, rootPos)
  groupLines.name = groupName
  return groupLines
}

// 生成标签和水滴图标
const getTextSprites = (
  { data, earthBallSize, visible, groupName }: any,
  fn: any
) => {
  const group = new THREE.Group()
  let offsetTop = 0
  const loop = function (items: any) {
    // console.log(items);
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      const position = getPosition(
        item.pos[0] - 90,
        item.pos[1],
        earthBallSize
      )
      const { x, y, z } = position
      const ballPos = new THREE.Vector3(x, y, z)

      // 标签
      if (item.showLabel) {
        const labelDiv = document.createElement('div')
        labelDiv.className = 'earth-label'
        labelDiv.textContent = item.name
        labelDiv.setAttribute('data-name', item.name)
        labelDiv.setAttribute('data-pos', item.pos.join(','))

        // labelDiv.onclick = function (e: any) {
        //   fn && fn(e.target.dataset);
        // };

        if (item.level === 0) {
          labelDiv.style.marginLeft = '200px'
          labelDiv.style.marginTop = -100 + offsetTop * 70 + 'px'
          offsetTop++
        }
        const earthLabel = new CSS2DObject(labelDiv)
        earthLabel.name = 'label_' + item.name
        earthLabel.position.set(ballPos.x, ballPos.y, ballPos.z)
        earthLabel.visible = visible
        group.add(earthLabel)
      }

      // 水滴
      if (item.showMask) {
        const dropDiv = document.createElement('div')
        dropDiv.setAttribute('data-name', item.name)
        dropDiv.setAttribute('data-pos', item.pos.join(','))
        switch (item.level) {
          case 0:
            dropDiv.className = 'drop-level-0'
            break
          case 1:
            dropDiv.className = 'drop-level-1'
            // dropDiv.onclick = function (e: any) {
            //   console.log(e, '######################')
            //   // fn && fn(e.target.dataset);
            // };
            break
          case 2:
            dropDiv.className = 'drop-level-2'
            dropDiv.onmouseover = function (e: any) {
              // console.log(e.target.dataset, 111);
              fn && fn(e)
            }
            break
          default:
            dropDiv.className = 'drop-level-0'
            break
        }
        const earthDrop = new CSS2DObject(dropDiv)
        earthDrop.name = 'label-drop'
        earthDrop.position.set(ballPos.x, ballPos.y, ballPos.z)
        earthDrop.visible = visible

        group.add(earthDrop)
      }

      if (item.children && item.children.length > 0) {
        loop(item.children)
      }
    }
  }
  loop(data)
  group.name = groupName
  return group
}

// 生成点标记
const getDotSprites = (
  data: any,
  earthBallSize: number,
  visible = true,
  groupName: string
) => {
  const group = new THREE.Group()
  const loop = function (items: any) {
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      const position = getPosition(
        item.pos[0] - 90,
        item.pos[1],
        earthBallSize
      )
      const ballPos = new THREE.Vector3(position.x, position.y, position.z)

      // 生成点
      const dropDiv = document.createElement('div')
      switch (item.type) {
        case 0:
          dropDiv.className = 'dot-type-0'
          break
        case 1:
          dropDiv.className = 'dot-type-1'
          break
        case 2:
          dropDiv.className = 'dot-type-2'
          break
        case 3:
          dropDiv.className = 'dot-type-3'
          break
        case 4:
          dropDiv.className = 'dot-type-4'
          break
        default:
          dropDiv.className = 'dot-type-0'
          break
      }
      const earthDrop = new CSS2DObject(dropDiv)
      earthDrop.name = 'label_dot_' + i
      earthDrop.position.set(ballPos.x, ballPos.y, ballPos.z)
      earthDrop.visible = visible
      group.add(earthDrop)
    }
  }
  loop(data)
  group.name = groupName
  return group
}

// 生成省份名字标签
const getProvinceSprites = (
  data: any,
  earthBallSize: number,
  visible = true,
  groupName: string,
  fn: any
) => {
  const group = new THREE.Group()
  const loop = function (items: any) {
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      const position = getPosition(
        item.pos[0] - 90,
        item.pos[1],
        earthBallSize
      )
      const { x, y, z } = position
      const ballPos = new THREE.Vector3(x, y, z)

      // 生成点
      const newDiv = document.createElement('div')
      newDiv.className = 'province_label'
      newDiv.textContent = item.name
      newDiv.onmouseover = (e: any) => {
        fn && fn(e)
      }
      const label = new CSS2DObject(newDiv)
      label.name = 'label_province_' + i
      label.position.set(ballPos.x, ballPos.y, ballPos.z)
      label.visible = visible
      group.add(label)
    }
  }
  loop(data)
  group.name = groupName
  return group
}

// 绘制飞线和label
const drawingFlyLine = (data: any, visible: boolean, fn: any) => {
  const { earth, flyingLineGroup, earthLableGroup } = data

  visible = !visible ? false : visible

  const newFlyingLineGroup = getFlyingLines(
    markingPos,
    earthBallSize,
    visible,
    FLYINGLINEGROUP
  )
  const params = {
    data: markingPos,
    earthBallSize: earthBallSize,
    visible: visible,
    groupName: EARTHLABEGROUP
  }

  const newEarthLableGroup = getTextSprites(params, fn)

  if (!flyingLineGroup) {
    earth.add(newFlyingLineGroup)
    // console.log(earth);
  } else {
    flyingLineGroup.add(...newFlyingLineGroup.children)
  }

  if (!earthLableGroup) {
    earth.add(newEarthLableGroup)
  } else {
    earthLableGroup.add(...newEarthLableGroup.children)
  }
}

// 绘制点标记
const drawingDots = async (data: any, visible: boolean) => {
  // console.log(data);
  const { dotGroup, earth } = data
  visible = !visible ? false : visible
  const newGroup = getDotSprites(
    getDotListPos(),
    earthBallSize,
    visible,
    DOTGROUP
  )
  if (!dotGroup) {
    earth && earth.add(newGroup)
  } else {
    if (dotGroup.children.length === 0) {
      dotGroup.add(...newGroup.children)
    }
  }
}

const newProvinceList = ref(provinceList)

// 绘制省份的leble
const drawingProvinceLabels = (data: any, visible: boolean, fn: any) => {
  // console.log(data);
  const { provinceLabelGroup, earth } = data
  visible = !visible ? false : visible

  const newGroup = getProvinceSprites(
    newProvinceList.value,
    earthBallSize,
    visible,
    PROVINCELABELGROUP,
    fn
  )

  if (!provinceLabelGroup) {
    earth.add(newGroup)
  } else {
    if (provinceLabelGroup.children.length === 0) {
      provinceLabelGroup.add(...newGroup.children)
    }
  }
}

// 边界线高亮
const boundaryLineHighlight = (data: any, object: any, event: any) => {
  const provinceName = object.name.split('-')[0]
  data.traverse((child: any) => {
    if (!child.material) return
    const name = child.name.split('-')[0]
    if (name === provinceName) {
      // console.log(child);
      if (child.name.indexOf(provinceName + '-省界') > -1) {
        const t = 1.01888
        // const t2 = 1.02888;
        child.material.emissiveIntensity = 1000
        child.scale.x = t
        child.scale.y = t
        child.scale.z = t
        // child.parent.scale.x = t2;
        // child.parent.scale.y = t2;
        // child.parent.scale.z = t2;
        // child.material.opacity = 0;
        // console.log(child);
      } else {
        const t = 1
        // const t2 = 1.01888;
        // child.material.emissiveIntensity = 1000;
        // child.material.opacity = 0;
        child.scale.x = t
        child.scale.y = t
        child.scale.z = t
        // child.parent.scale.x = t2;
        // child.parent.scale.y = t2;
        // child.parent.scale.z = t2;
      }
    } else {
      const t = 1
      child.scale.x = t
      child.scale.y = t
      child.scale.z = t
      child.material.emissiveIntensity = 0
    }
  })
}

// 省份高亮升起
const provinceHighlight = (data: any, object: any) => {
  // 获取省份模型
  const name = object.name.split('-')[0]
  if (!data) return
  data.traverse((child: any) => {
    const childName = child.name.split('-')[0]
    if (child.material) {
      if (childName === name) {
        const t = 1.008
        object.scale.x = t
        object.scale.y = t
        object.scale.z = t
      } else {
        const t = 1
        child.scale.x = t
        child.scale.y = t
        child.scale.z = t
      }
    }
  })
}

/**
 * 移除省会名称 分省份销售
 */
const removeProvinceLabel = () => {
  const groupName = 'provinceLabelGroup'
  const oldGroup: any = scene.getObjectByName(groupName)
  if (!oldGroup) return
  const allChildren = oldGroup.children
  for (let i = allChildren.length - 1; i >= 0; i--) {
    oldGroup.remove(allChildren[i])
  }
}

/**
 * 移除点，客户分布数据
 */
const removeDots = () => {
  const groupName = 'dotGroup'
  const oldGroup: any = scene.getObjectByName(groupName)
  // console.log(oldGroup, '111111111111111111111');
  if (!oldGroup) return
  const allChildren = oldGroup.children
  for (let i = allChildren.length - 1; i >= 0; i--) {
    oldGroup.remove(allChildren[i])
  }
}

/**
 * 移除销售网络分布数据  地图1数据
 */
const removeFlyLine = () => {
  const groupName1 = 'flyingLineGroup'
  const groupName2 = 'earthLableGroup'

  const oldFlyingLineGroup: any = scene.getObjectByName(groupName1)
  const oldEarthLableGroup: any = scene.getObjectByName(groupName2)
  if (!oldFlyingLineGroup || !oldEarthLableGroup) return
  // console.log(oldFlyingLineGroup, '============');
  // console.log(oldEarthLableGroup, '============');
  const allChildren1 = oldFlyingLineGroup?.children
  for (var i = allChildren1.length - 1; i >= 0; i--) {
    oldFlyingLineGroup.remove(allChildren1[i])
  }

  const allChildren2 = oldEarthLableGroup?.children
  for (var i = allChildren2.length - 1; i >= 0; i--) {
    oldEarthLableGroup.remove(allChildren2[i])
  }
}

// 场景切换
/**
 * @param type // 1 销售网络分布 2 客户分布  3分省份销售
 * @param model // 地球模型
 * @param fn // 分省份销售鼠标滑过事件
 * @param showOfficeName  // 销售网络分布鼠标滑过时显示办事处名称
 * @param allProvinceObject  // 地球上所有省份
 */
const onChange = (type: number, model: any, fn: any, showOfficeName: any) => {
  const earth = model.getObjectByName('earthModel')
  const groupData = {
    flyingLineGroup: model.getObjectByName(FLYINGLINEGROUP),
    earthLableGroup: model.getObjectByName(EARTHLABEGROUP),
    dotGroup: model.getObjectByName(DOTGROUP),
    provinceLabelGroup: model.getObjectByName(PROVINCELABELGROUP),
    earth
  }

  const { flyingLineGroup, earthLableGroup, dotGroup, provinceLabelGroup } =
    groupData
  state.eventType = type
  const groupArr = [
    flyingLineGroup,
    earthLableGroup,
    dotGroup,
    provinceLabelGroup
  ]

  groupArr.forEach((group: GroupType) => {
    if (!group) return
    group.visible = false
    group.traverse((child: any) => {
      child.visible = false
    })
  })
  const allProvinceObject = model.getObjectByName('省份')
  const Japan = model.getObjectByName('日本')
  const SouthKorea = model.getObjectByName('韩国')

  switch (type) {
    case 1:
      // 制作飞线
      drawingFlyLine(groupData, true, showOfficeName)
      getGroupName(flyingLineGroup)
      allProvinceObject && removeColor(allProvinceObject)
      getGroupName(earthLableGroup)
      removeProvinceLabel()
      removeDots()
      break
    case 2:
      // 绘制点标记
      drawingDots(groupData, true)
      getGroupName(dotGroup)
      allProvinceObject && removeColor(allProvinceObject)
      removeProvinceLabel()
      removeFlyLine()
      break
    case 3:
      // 绘制省份的leble
      drawingProvinceLabels(groupData, true, fn)
      getGroupName(provinceLabelGroup)
      removeDots()
      removeFlyLine()
      allProvinceObject && changeColor(allProvinceObject)
      console.log('----------')
      console.log(Japan)
      console.log(allProvinceObject)
      Japan && changeColor(Japan)
      SouthKorea && changeColor(SouthKorea)
      break
    default:
      break
  }
}

const getGroupName = (group: any) => {
  if (!group) return
  group.visible = true
  group.traverse(function (child: any) {
    child.visible = true
    if (
      !localStorage.getItem('showExitusData') &&
      group.name === 'provinceLabelGroup'
    ) {
      if (
        child.name === 'label_province_35' ||
        child.name === 'label_province_34'
      ) {
        child.visible = false
      } else {
        child.visible = true
      }
    }
  })
}

/**
 * 默认地图颜色
 * @param model 模型数据
 */
const removeColor = (model: any) => {
  model.traverse((child: any) => {
    if (!child.material) return
    provinceList.forEach((item) => {
      if (child.name.split('-')[0] === item.name) {
        const t = 0.9857054948806763
        child.parent.scale.x = t
        child.parent.scale.y = t
        child.parent.scale.z = t
        child.material.emissiveIntensity = 0
      }
    })
  })
}

/**
 * 当点击分省份销售时改变模型中地图上的颜色
 * @param model 模型数据
 */
const changeColor = (model: any) => {
  let i = 1
  model.traverse((child: any) => {
    if (!child.material) return
    console.log(child, child.name.split('-')[0])
    provinceList.forEach((item) => {
      if (child.name.split('-')[0] === item.name) {
        i = 10 * item.heat
        const t = 1.008
        child.parent.scale.x = t
        child.parent.scale.y = t
        child.parent.scale.z = t
        child.material.opacity = 1
        // child.material.color = 0x009e60;
        console.log('---------')
        child.material.emissive = 0x009e60
        // child.material.emissiveIntensity = i;
      }
    })
  })
  // console.log(model);
}

export {
  state,
  drawingFlyLine,
  drawingDots,
  drawingProvinceLabels,
  boundaryLineHighlight,
  provinceHighlight,
  onChange
}
